bitkeeper revision 1.22.2.11 (3e465c080oDmXRHMT2ue0NRHdbJL3g)
authorkaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk>
Sun, 9 Feb 2003 13:47:52 +0000 (13:47 +0000)
committerkaf24@labyrinth.cl.cam.ac.uk <kaf24@labyrinth.cl.cam.ac.uk>
Sun, 9 Feb 2003 13:47:52 +0000 (13:47 +0000)
ne.c, Makefile, 8390.h, 8390.c, in.h, config.h, kernel.c, Rules.mk:
  Ported NE2K driver for Bochs development. Also some minor cleanups.
ne.c, Makefile, 8390.h, 8390.c:
  new file

.rootkeys
xen-2.4.16/Makefile
xen-2.4.16/arch/i386/Rules.mk
xen-2.4.16/common/kernel.c
xen-2.4.16/drivers/net/Makefile
xen-2.4.16/drivers/net/ne/8390.c [new file with mode: 0644]
xen-2.4.16/drivers/net/ne/8390.h [new file with mode: 0644]
xen-2.4.16/drivers/net/ne/Makefile [new file with mode: 0644]
xen-2.4.16/drivers/net/ne/ne.c [new file with mode: 0644]
xen-2.4.16/include/xeno/config.h
xen-2.4.16/include/xeno/in.h

index df2094291ccdc7b16cc08d54aa8709bd5bff289e..a3e6a0d4fae26b470b4728fe6d0c9e5a4caf929f 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3e4540cc3t7_y-YLeyMG2pX9xtdXPA xen-2.4.16/drivers/net/e1000/e1000_osdep.h
 3e4540cct_8Ig-Y1W_vM2gS_u7mC0A xen-2.4.16/drivers/net/e1000/e1000_param.c
 3ddb79c0GejJrp1U6W4G6dYi-RiH4A xen-2.4.16/drivers/net/eepro100.c
+3e465c00t2nochqR27eEY_FBjxsUCw xen-2.4.16/drivers/net/ne/8390.c
+3e465c00AIRmk20x1vYETtnL71eGvA xen-2.4.16/drivers/net/ne/8390.h
+3e465c00UIvPTAtAcgcQWCVFa2bwww xen-2.4.16/drivers/net/ne/Makefile
+3e465c00rWSHiXmHuOWLRf7r2n8S3g xen-2.4.16/drivers/net/ne/ne.c
 3ddb79bfKvn9mt0kofpkw0QaWjxO6A xen-2.4.16/drivers/net/net_init.c
 3ddb79c0fQgORkFlqWZdP-6cDHyFIQ xen-2.4.16/drivers/net/pcnet32.c
 3ddb79bf_CBcu3QWYwq4bNAOnM2RqQ xen-2.4.16/drivers/net/setup.c
index 82837d99a173af4564b3e440a23e889bb4eae6f4..3bd4299075b66d8746ac4dddda6b7518981c982d 100644 (file)
@@ -5,7 +5,7 @@ include Rules.mk
 
 default: $(TARGET)
        gzip -f -9 < $(TARGET) > $(TARGET).gz
-       objdump -D -S image >image.s
+#      objdump -D -S image >image.s
 
 install: $(TARGET)
        gzip -f -9 < $(TARGET) > $(TARGET).gz
index 28d24fd0a44dd499590dc99b0a0f54423b779b5b..8a672e228a88c38b587eb567dbe9026769feef79 100644 (file)
@@ -8,7 +8,7 @@ MONITOR_BASE := 0xFC500000
 # Bootloader should load monitor to this real address
 LOAD_BASE    := 0x00100000
 CFLAGS  := -nostdinc -fno-builtin -O3 -Wall -DMONITOR_BASE=$(MONITOR_BASE) 
-CFLAGS  += -I$(BASEDIR)/include -D__KERNEL__ -DNDEBUG
+CFLAGS  += -fomit-frame-pointer -I$(BASEDIR)/include -D__KERNEL__ -DNDEBUG
 LDFLAGS := -T xeno.lds -N
 
 
index fe67b0f14b46471755d2a0f6bd90e2eed9afccfa..04c3b1d0b78bba320f4212f79d1de9e91774cd4b 100644 (file)
@@ -43,6 +43,7 @@ void start_of_day(void);
 unsigned long opt_ipbase=0, opt_nfsserv=0, opt_gateway=0, opt_netmask=0;
 unsigned char opt_nfsroot[50]="";
 unsigned int opt_dom0_mem = 16000; /* default kbytes for DOM0 */
+unsigned int opt_ne_base = 0; /* NE2k NICs cannot be probed */
 enum { OPT_IP, OPT_STR, OPT_UINT };
 static struct {
     unsigned char *name;
@@ -55,6 +56,7 @@ static struct {
     { "netmask",  OPT_IP,   &opt_netmask },
     { "nfsroot",  OPT_STR,  &opt_nfsroot },
     { "dom0_mem", OPT_UINT, &opt_dom0_mem }, 
+    { "ne_base",  OPT_UINT, &opt_ne_base },
     { NULL,       0,        NULL     }
 };
 
@@ -143,7 +145,8 @@ void cmain (unsigned long magic, multiboot_info_t *mbi)
                     }
                     else /* opts[i].type == OPT_UINT */
                     {
-                        *(unsigned int *)opts[i].var = simple_strtol(opt, (char **)&opt, 10);
+                        *(unsigned int *)opts[i].var =
+                            simple_strtol(opt, (char **)&opt, 0);
                     }
                     break;
                 }
index 54d48823edb06dc29cf3f4d3c3a555b2ae94934d..8b752b9712ec5a338cd7a9d7fc17a18094cf81ac 100644 (file)
@@ -2,11 +2,15 @@
 include $(BASEDIR)/Rules.mk
 
 default: $(OBJS)
+       $(MAKE) -C ne
        $(MAKE) -C tulip
        $(MAKE) -C e1000
-       $(LD) -r -o driver.o $(OBJS) tulip/tulip.o e1000/e1000.o
+       $(LD) -r -o driver.o $(OBJS) tulip/tulip.o e1000/e1000.o ne/ne_drv.o
 
 clean:
+       $(MAKE) -C ne clean
        $(MAKE) -C tulip clean
        $(MAKE) -C e1000 clean
        rm -f *.o *~ core
+
+.PHONY: default clean
diff --git a/xen-2.4.16/drivers/net/ne/8390.c b/xen-2.4.16/drivers/net/ne/8390.c
new file mode 100644 (file)
index 0000000..aa299a3
--- /dev/null
@@ -0,0 +1,1158 @@
+/* 8390.c: A general NS8390 ethernet driver core for linux. */
+/*
+       Written 1992-94 by Donald Becker.
+  
+       Copyright 1993 United States Government as represented by the
+       Director, National Security Agency.
+
+       This software may be used and distributed according to the terms
+       of the GNU General Public License, incorporated herein by reference.
+
+       The author may be reached as becker@scyld.com, or C/O
+       Scyld Computing Corporation
+       410 Severn Ave., Suite 210
+       Annapolis MD 21403
+
+  
+  This is the chip-specific code for many 8390-based ethernet adaptors.
+  This is not a complete driver, it must be combined with board-specific
+  code such as ne.c, wd.c, 3c503.c, etc.
+
+  Seeing how at least eight drivers use this code, (not counting the
+  PCMCIA ones either) it is easy to break some card by what seems like
+  a simple innocent change. Please contact me or Donald if you think
+  you have found something that needs changing. -- PG
+
+
+  Changelog:
+
+  Paul Gortmaker       : remove set_bit lock, other cleanups.
+  Paul Gortmaker       : add ei_get_8390_hdr() so we can pass skb's to 
+                         ei_block_input() for eth_io_copy_and_sum().
+  Paul Gortmaker       : exchange static int ei_pingpong for a #define,
+                         also add better Tx error handling.
+  Paul Gortmaker       : rewrite Rx overrun handling as per NS specs.
+  Alexey Kuznetsov     : use the 8390's six bit hash multicast filter.
+  Paul Gortmaker       : tweak ANK's above multicast changes a bit.
+  Paul Gortmaker       : update packet statistics for v2.1.x
+  Alan Cox             : support arbitary stupid port mappings on the
+                         68K Macintosh. Support >16bit I/O spaces
+  Paul Gortmaker       : add kmod support for auto-loading of the 8390
+                         module by all drivers that require it.
+  Alan Cox             : Spinlocking work, added 'BUG_83C690'
+  Paul Gortmaker       : Separate out Tx timeout code from Tx path.
+
+  Sources:
+  The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+
+  */
+
+static const char version[] =
+    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+
+#include <xeno/module.h>
+#include <xeno/kernel.h>
+#include <xeno/sched.h>
+//#include <xeno/fs.h>
+#include <xeno/types.h>
+//#include <xeno/ptrace.h>
+#include <xeno/lib.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <xeno/delay.h>
+#include <xeno/errno.h>
+//#include <xeno/fcntl.h>
+#include <xeno/in.h>
+#include <xeno/interrupt.h>
+#include <xeno/init.h>
+
+#include <xeno/netdevice.h>
+#include <xeno/etherdevice.h>
+
+#define NS8390_CORE
+#include "8390.h"
+
+#define BUG_83C690
+
+/* These are the operational function interfaces to board-specific
+   routines.
+       void reset_8390(struct net_device *dev)
+               Resets the board associated with DEV, including a hardware reset of
+               the 8390.  This is only called when there is a transmit timeout, and
+               it is always followed by 8390_init().
+       void block_output(struct net_device *dev, int count, const unsigned char *buf,
+                                         int start_page)
+               Write the COUNT bytes of BUF to the packet buffer at START_PAGE.  The
+               "page" value uses the 8390's 256-byte pages.
+       void get_8390_hdr(struct net_device *dev, struct e8390_hdr *hdr, int ring_page)
+               Read the 4 byte, page aligned 8390 header. *If* there is a
+               subsequent read, it will be of the rest of the packet.
+       void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+               Read COUNT bytes from the packet buffer into the skb data area. Start 
+               reading from RING_OFFSET, the address as the 8390 sees it.  This will always
+               follow the read of the 8390 header. 
+*/
+#define ei_reset_8390 (ei_local->reset_8390)
+#define ei_block_output (ei_local->block_output)
+#define ei_block_input (ei_local->block_input)
+#define ei_get_8390_hdr (ei_local->get_8390_hdr)
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef ei_debug
+int ei_debug = 1;
+#endif
+
+/* Index to functions. */
+static void ei_tx_intr(struct net_device *dev);
+static void ei_tx_err(struct net_device *dev);
+static void ei_tx_timeout(struct net_device *dev);
+static void ei_receive(struct net_device *dev);
+static void ei_rx_overrun(struct net_device *dev);
+
+/* Routines generic to NS8390-based boards. */
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+                                                               int start_page);
+static void set_multicast_list(struct net_device *dev);
+static void do_set_multicast_list(struct net_device *dev);
+
+/*
+ *     SMP and the 8390 setup.
+ *
+ *     The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
+ *     a page register that controls bank and packet buffer access. We guard
+ *     this with ei_local->page_lock. Nobody should assume or set the page other
+ *     than zero when the lock is not held. Lock holders must restore page 0
+ *     before unlocking. Even pure readers must take the lock to protect in 
+ *     page 0.
+ *
+ *     To make life difficult the chip can also be very slow. We therefore can't
+ *     just use spinlocks. For the longer lockups we disable the irq the device
+ *     sits on and hold the lock. We must hold the lock because there is a dual
+ *     processor case other than interrupts (get stats/set multicast list in
+ *     parallel with each other and transmit).
+ *
+ *     Note: in theory we can just disable the irq on the card _but_ there is
+ *     a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
+ *     enter lock, take the queued irq. So we waddle instead of flying.
+ *
+ *     Finally by special arrangement for the purpose of being generally 
+ *     annoying the transmit function is called bh atomic. That places
+ *     restrictions on the user context callers as disable_irq won't save
+ *     them.
+ */
+
+\f
+/**
+ * ei_open - Open/initialize the board.
+ * @dev: network device to initialize
+ *
+ * This routine goes all-out, setting everything
+ * up anew at each open, even though many of these registers should only
+ * need to be set once at boot.
+ */
+int ei_open(struct net_device *dev)
+{
+       unsigned long flags;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+       /* This can't happen unless somebody forgot to call ethdev_init(). */
+       if (ei_local == NULL) 
+       {
+               printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name);
+               return -ENXIO;
+       }
+       
+       /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout
+           wrapper that does e.g. media check & then calls ei_tx_timeout. */
+       if (dev->tx_timeout == NULL)
+                dev->tx_timeout = ei_tx_timeout;
+       if (dev->watchdog_timeo <= 0)
+                dev->watchdog_timeo = TX_TIMEOUT;
+    
+       /*
+        *      Grab the page lock so we own the register set, then call
+        *      the init function.
+        */
+      
+       spin_lock_irqsave(&ei_local->page_lock, flags);
+       NS8390_init(dev, 1);
+       /* Set the flag before we drop the lock, That way the IRQ arrives
+          after its set and we get no silly warnings */
+       netif_start_queue(dev);
+       spin_unlock_irqrestore(&ei_local->page_lock, flags);
+       ei_local->irqlock = 0;
+       return 0;
+}
+
+/**
+ * ei_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ei_open(). Only used when "ifconfig <devname> down" is done.
+ */
+int ei_close(struct net_device *dev)
+{
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       unsigned long flags;
+
+       /*
+        *      Hold the page lock during close
+        */
+               
+       spin_lock_irqsave(&ei_local->page_lock, flags);
+       NS8390_init(dev, 0);
+       spin_unlock_irqrestore(&ei_local->page_lock, flags);
+       netif_stop_queue(dev);
+       return 0;
+}
+
+/**
+ * ei_tx_timeout - handle transmit time out condition
+ * @dev: network device which has apparently fallen asleep
+ *
+ * Called by kernel when device never acknowledges a transmit has
+ * completed (or failed) - i.e. never posted a Tx related interrupt.
+ */
+
+void ei_tx_timeout(struct net_device *dev)
+{
+       long e8390_base = dev->base_addr;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       int txsr, isr, tickssofar = jiffies - dev->trans_start;
+       unsigned long flags;
+
+       ei_local->stat.tx_errors++;
+
+       spin_lock_irqsave(&ei_local->page_lock, flags);
+       txsr = inb(e8390_base+EN0_TSR);
+       isr = inb(e8390_base+EN0_ISR);
+       spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+       printk(KERN_DEBUG "%s: Tx timed out, %s TSR=%#2x, ISR=%#2x, t=%d.\n",
+               dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
+               (isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
+
+       if (!isr && !ei_local->stat.tx_packets) 
+       {
+               /* The 8390 probably hasn't gotten on the cable yet. */
+               ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
+       }
+
+       /* Ugly but a reset can be slow, yet must be protected */
+               
+       disable_irq_nosync(dev->irq);
+       spin_lock(&ei_local->page_lock);
+               
+       /* Try to restart the card.  Perhaps the user has fixed something. */
+       ei_reset_8390(dev);
+       NS8390_init(dev, 1);
+               
+       spin_unlock(&ei_local->page_lock);
+       enable_irq(dev->irq);
+       netif_wake_queue(dev);
+}
+    
+/**
+ * ei_start_xmit - begin packet transmission
+ * @skb: packet to be sent
+ * @dev: network device to which packet is sent
+ *
+ * Sends a packet to an 8390 network device.
+ */
+static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       long e8390_base = dev->base_addr;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       int length, send_length, output_page;
+       unsigned long flags;
+
+       length = skb->len;
+
+       /* Mask interrupts from the ethercard. 
+          SMP: We have to grab the lock here otherwise the IRQ handler
+          on another CPU can flip window and race the IRQ mask set. We end
+          up trashing the mcast filter not disabling irqs if we dont lock */
+          
+       spin_lock_irqsave(&ei_local->page_lock, flags);
+       outb_p(0x00, e8390_base + EN0_IMR);
+       spin_unlock_irqrestore(&ei_local->page_lock, flags);
+       
+       
+       /*
+        *      Slow phase with lock held.
+        */
+        
+       disable_irq_nosync(dev->irq);
+       
+       spin_lock(&ei_local->page_lock);
+       
+       ei_local->irqlock = 1;
+
+       send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
+    
+#ifdef EI_PINGPONG
+
+       /*
+        * We have two Tx slots available for use. Find the first free
+        * slot, and then perform some sanity checks. With two Tx bufs,
+        * you get very close to transmitting back-to-back packets. With
+        * only one Tx buf, the transmitter sits idle while you reload the
+        * card, leaving a substantial gap between each transmitted packet.
+        */
+
+       if (ei_local->tx1 == 0) 
+       {
+               output_page = ei_local->tx_start_page;
+               ei_local->tx1 = send_length;
+               if (ei_debug  &&  ei_local->tx2 > 0)
+                       printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+                               dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
+       }
+       else if (ei_local->tx2 == 0) 
+       {
+               output_page = ei_local->tx_start_page + TX_1X_PAGES;
+               ei_local->tx2 = send_length;
+               if (ei_debug  &&  ei_local->tx1 > 0)
+                       printk(KERN_DEBUG "%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+                               dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing);
+       }
+       else
+       {       /* We should never get here. */
+               if (ei_debug)
+                       printk(KERN_DEBUG "%s: No Tx buffers free! tx1=%d tx2=%d last=%d\n",
+                               dev->name, ei_local->tx1, ei_local->tx2, ei_local->lasttx);
+               ei_local->irqlock = 0;
+               netif_stop_queue(dev);
+               outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+               spin_unlock(&ei_local->page_lock);
+               enable_irq(dev->irq);
+               ei_local->stat.tx_errors++;
+               return 1;
+       }
+
+       /*
+        * Okay, now upload the packet and trigger a send if the transmitter
+        * isn't already sending. If it is busy, the interrupt handler will
+        * trigger the send later, upon receiving a Tx done interrupt.
+        */
+
+       ei_block_output(dev, length, skb->data, output_page);
+       if (! ei_local->txing) 
+       {
+               ei_local->txing = 1;
+               NS8390_trigger_send(dev, send_length, output_page);
+               dev->trans_start = jiffies;
+               if (output_page == ei_local->tx_start_page) 
+               {
+                       ei_local->tx1 = -1;
+                       ei_local->lasttx = -1;
+               }
+               else 
+               {
+                       ei_local->tx2 = -1;
+                       ei_local->lasttx = -2;
+               }
+       }
+       else ei_local->txqueue++;
+
+       if (ei_local->tx1  &&  ei_local->tx2)
+               netif_stop_queue(dev);
+       else
+               netif_start_queue(dev);
+
+#else  /* EI_PINGPONG */
+
+       /*
+        * Only one Tx buffer in use. You need two Tx bufs to come close to
+        * back-to-back transmits. Expect a 20 -> 25% performance hit on
+        * reasonable hardware if you only use one Tx buffer.
+        */
+
+       ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
+       ei_local->txing = 1;
+       NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
+       dev->trans_start = jiffies;
+       netif_stop_queue(dev);
+
+#endif /* EI_PINGPONG */
+
+       /* Turn 8390 interrupts back on. */
+       ei_local->irqlock = 0;
+       outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+       
+       spin_unlock(&ei_local->page_lock);
+       enable_irq(dev->irq);
+
+       dev_kfree_skb (skb);
+       ei_local->stat.tx_bytes += send_length;
+    
+       return 0;
+}
+\f
+/**
+ * ei_interrupt - handle the interrupts from an 8390
+ * @irq: interrupt number
+ * @dev_id: a pointer to the net_device
+ * @regs: unused
+ *
+ * Handle the ether interface interrupts. We pull packets from
+ * the 8390 via the card specific functions and fire them at the networking
+ * stack. We also handle transmit completions and wake the transmit path if
+ * neccessary. We also update the counters and do other housekeeping as
+ * needed.
+ */
+
+void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+       struct net_device *dev = dev_id;
+       long e8390_base;
+       int interrupts, nr_serviced = 0;
+       struct ei_device *ei_local;
+    
+       if (dev == NULL) 
+       {
+               printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+               return;
+       }
+    
+       e8390_base = dev->base_addr;
+       ei_local = (struct ei_device *) dev->priv;
+
+       /*
+        *      Protect the irq test too.
+        */
+        
+       spin_lock(&ei_local->page_lock);
+
+       if (ei_local->irqlock) 
+       {
+#if 1 /* This might just be an interrupt for a PCI device sharing this line */
+               /* The "irqlock" check is only for testing. */
+               printk(ei_local->irqlock
+                          ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
+                          : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
+                          dev->name, inb_p(e8390_base + EN0_ISR),
+                          inb_p(e8390_base + EN0_IMR));
+#endif
+               spin_unlock(&ei_local->page_lock);
+               return;
+       }
+    
+       /* Change to page 0 and read the intr status reg. */
+       outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+       if (ei_debug > 3)
+               printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
+                          inb_p(e8390_base + EN0_ISR));
+    
+       /* !!Assumption!! -- we stay in page 0.  Don't break this. */
+       while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
+                  && ++nr_serviced < MAX_SERVICE) 
+       {
+               if (!netif_running(dev)) {
+                       printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
+                       /* rmk - acknowledge the interrupts */
+                       outb_p(interrupts, e8390_base + EN0_ISR);
+                       interrupts = 0;
+                       break;
+               }
+               if (interrupts & ENISR_OVER) 
+                       ei_rx_overrun(dev);
+               else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) 
+               {
+                       /* Got a good (?) packet. */
+                       ei_receive(dev);
+               }
+               /* Push the next to-transmit packet through. */
+               if (interrupts & ENISR_TX)
+                       ei_tx_intr(dev);
+               else if (interrupts & ENISR_TX_ERR)
+                       ei_tx_err(dev);
+
+               if (interrupts & ENISR_COUNTERS) 
+               {
+                       ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
+                       ei_local->stat.rx_crc_errors   += inb_p(e8390_base + EN0_COUNTER1);
+                       ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
+                       outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
+               }
+               
+               /* Ignore any RDC interrupts that make it back to here. */
+               if (interrupts & ENISR_RDC) 
+               {
+                       outb_p(ENISR_RDC, e8390_base + EN0_ISR);
+               }
+
+               outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+       }
+    
+       if (interrupts && ei_debug) 
+       {
+               outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+               if (nr_serviced >= MAX_SERVICE) 
+               {
+                       /* 0xFF is valid for a card removal */
+                       if(interrupts!=0xFF)
+                               printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
+                                  dev->name, interrupts);
+                       outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
+               } else {
+                       printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
+                       outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+               }
+       }
+       spin_unlock(&ei_local->page_lock);
+       return;
+}
+
+/**
+ * ei_tx_err - handle transmitter error
+ * @dev: network device which threw the exception
+ *
+ * A transmitter error has happened. Most likely excess collisions (which
+ * is a fairly normal condition). If the error is one where the Tx will
+ * have been aborted, we try and send another one right away, instead of
+ * letting the failed packet sit and collect dust in the Tx buffer. This
+ * is a much better solution as it avoids kernel based Tx timeouts, and
+ * an unnecessary card reset.
+ *
+ * Called with lock held.
+ */
+
+static void ei_tx_err(struct net_device *dev)
+{
+       long e8390_base = dev->base_addr;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       unsigned char txsr = inb_p(e8390_base+EN0_TSR);
+       unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+
+#ifdef VERBOSE_ERROR_DUMP
+       printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
+       if (txsr & ENTSR_ABT)
+               printk("excess-collisions ");
+       if (txsr & ENTSR_ND)
+               printk("non-deferral ");
+       if (txsr & ENTSR_CRS)
+               printk("lost-carrier ");
+       if (txsr & ENTSR_FU)
+               printk("FIFO-underrun ");
+       if (txsr & ENTSR_CDH)
+               printk("lost-heartbeat ");
+       printk("\n");
+#endif
+
+       outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+
+       if (tx_was_aborted)
+               ei_tx_intr(dev);
+       else 
+       {
+               ei_local->stat.tx_errors++;
+               if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
+               if (txsr & ENTSR_CDH) ei_local->stat.tx_heartbeat_errors++;
+               if (txsr & ENTSR_OWC) ei_local->stat.tx_window_errors++;
+       }
+}
+
+/**
+ * ei_tx_intr - transmit interrupt handler
+ * @dev: network device for which tx intr is handled
+ *
+ * We have finished a transmit: check for errors and then trigger the next
+ * packet to be sent. Called with lock held.
+ */
+
+static void ei_tx_intr(struct net_device *dev)
+{
+       long e8390_base = dev->base_addr;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       int status = inb(e8390_base + EN0_TSR);
+    
+       outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
+
+#ifdef EI_PINGPONG
+
+       /*
+        * There are two Tx buffers, see which one finished, and trigger
+        * the send of another one if it exists.
+        */
+       ei_local->txqueue--;
+
+       if (ei_local->tx1 < 0) 
+       {
+               if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+                       printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
+                               ei_local->name, ei_local->lasttx, ei_local->tx1);
+               ei_local->tx1 = 0;
+               if (ei_local->tx2 > 0) 
+               {
+                       ei_local->txing = 1;
+                       NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+                       dev->trans_start = jiffies;
+                       ei_local->tx2 = -1,
+                       ei_local->lasttx = 2;
+               }
+               else ei_local->lasttx = 20, ei_local->txing = 0;        
+       }
+       else if (ei_local->tx2 < 0) 
+       {
+               if (ei_local->lasttx != 2  &&  ei_local->lasttx != -2)
+                       printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+                               ei_local->name, ei_local->lasttx, ei_local->tx2);
+               ei_local->tx2 = 0;
+               if (ei_local->tx1 > 0) 
+               {
+                       ei_local->txing = 1;
+                       NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+                       dev->trans_start = jiffies;
+                       ei_local->tx1 = -1;
+                       ei_local->lasttx = 1;
+               }
+               else
+                       ei_local->lasttx = 10, ei_local->txing = 0;
+       }
+//     else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
+//                     dev->name, ei_local->lasttx);
+
+#else  /* EI_PINGPONG */
+       /*
+        *  Single Tx buffer: mark it free so another packet can be loaded.
+        */
+       ei_local->txing = 0;
+#endif
+
+       /* Minimize Tx latency: update the statistics after we restart TXing. */
+       if (status & ENTSR_COL)
+               ei_local->stat.collisions++;
+       if (status & ENTSR_PTX)
+               ei_local->stat.tx_packets++;
+       else 
+       {
+               ei_local->stat.tx_errors++;
+               if (status & ENTSR_ABT) 
+               {
+                       ei_local->stat.tx_aborted_errors++;
+                       ei_local->stat.collisions += 16;
+               }
+               if (status & ENTSR_CRS) 
+                       ei_local->stat.tx_carrier_errors++;
+               if (status & ENTSR_FU) 
+                       ei_local->stat.tx_fifo_errors++;
+               if (status & ENTSR_CDH)
+                       ei_local->stat.tx_heartbeat_errors++;
+               if (status & ENTSR_OWC)
+                       ei_local->stat.tx_window_errors++;
+       }
+       netif_wake_queue(dev);
+}
+
+/**
+ * ei_receive - receive some packets
+ * @dev: network device with which receive will be run
+ *
+ * We have a good packet(s), get it/them out of the buffers. 
+ * Called with lock held.
+ */
+
+static void ei_receive(struct net_device *dev)
+{
+       long e8390_base = dev->base_addr;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       unsigned char rxing_page, this_frame, next_frame;
+       unsigned short current_offset;
+       int rx_pkt_count = 0;
+       struct e8390_pkt_hdr rx_frame;
+       int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
+    
+       while (++rx_pkt_count < 10) 
+       {
+               int pkt_len, pkt_stat;
+               
+               /* Get the rx page (incoming packet pointer). */
+               outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
+               rxing_page = inb_p(e8390_base + EN1_CURPAG);
+               outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+               
+               /* Remove one frame from the ring.  Boundary is always a page behind. */
+               this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
+               if (this_frame >= ei_local->stop_page)
+                       this_frame = ei_local->rx_start_page;
+               
+               /* Someday we'll omit the previous, iff we never get this message.
+                  (There is at least one clone claimed to have a problem.)  
+                  
+                  Keep quiet if it looks like a card removal. One problem here
+                  is that some clones crash in roughly the same way.
+                */
+               if (ei_debug > 0  &&  this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
+                       printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
+                                  dev->name, this_frame, ei_local->current_page);
+               
+               if (this_frame == rxing_page)   /* Read all the frames? */
+                       break;                          /* Done for now */
+               
+               current_offset = this_frame << 8;
+               ei_get_8390_hdr(dev, &rx_frame, this_frame);
+               
+               pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
+               pkt_stat = rx_frame.status;
+               
+               next_frame = this_frame + 1 + ((pkt_len+4)>>8);
+               
+               /* Check for bogosity warned by 3c503 book: the status byte is never
+                  written.  This happened a lot during testing! This code should be
+                  cleaned up someday. */
+               if (rx_frame.next != next_frame
+                       && rx_frame.next != next_frame + 1
+                       && rx_frame.next != next_frame - num_rx_pages
+                       && rx_frame.next != next_frame + 1 - num_rx_pages) {
+                       ei_local->current_page = rxing_page;
+                       outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
+                       ei_local->stat.rx_errors++;
+                       continue;
+               }
+
+               if (pkt_len < 60  ||  pkt_len > 1518) 
+               {
+                       if (ei_debug)
+                               printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
+                                          dev->name, rx_frame.count, rx_frame.status,
+                                          rx_frame.next);
+                       ei_local->stat.rx_errors++;
+                       ei_local->stat.rx_length_errors++;
+               }
+                else if ((pkt_stat & 0x0F) == ENRSR_RXOK) 
+               {
+                       struct sk_buff *skb;
+                       
+                       skb = dev_alloc_skb(pkt_len+2);
+                       if (skb == NULL) 
+                       {
+                               if (ei_debug > 1)
+                                       printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
+                                                  dev->name, pkt_len);
+                               ei_local->stat.rx_dropped++;
+                               break;
+                       }
+                       else
+                       {
+                               skb_reserve(skb,2);     /* IP headers on 16 byte boundaries */
+                               skb->dev = dev;
+                               skb_put(skb, pkt_len);  /* Make room */
+                               ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame));
+                               skb->protocol=eth_type_trans(skb,dev);
+                               netif_rx(skb);
+                               dev->last_rx = jiffies;
+                               ei_local->stat.rx_packets++;
+                               ei_local->stat.rx_bytes += pkt_len;
+                               if (pkt_stat & ENRSR_PHY)
+                                       ei_local->stat.multicast++;
+                       }
+               } 
+               else 
+               {
+                       if (ei_debug)
+                               printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
+                                          dev->name, rx_frame.status, rx_frame.next,
+                                          rx_frame.count);
+                       ei_local->stat.rx_errors++;
+                       /* NB: The NIC counts CRC, frame and missed errors. */
+                       if (pkt_stat & ENRSR_FO)
+                               ei_local->stat.rx_fifo_errors++;
+               }
+               next_frame = rx_frame.next;
+               
+               /* This _should_ never happen: it's here for avoiding bad clones. */
+               if (next_frame >= ei_local->stop_page) {
+                       printk("%s: next frame inconsistency, %#2x\n", dev->name,
+                                  next_frame);
+                       next_frame = ei_local->rx_start_page;
+               }
+               ei_local->current_page = next_frame;
+               outb_p(next_frame-1, e8390_base+EN0_BOUNDARY);
+       }
+
+       /* We used to also ack ENISR_OVER here, but that would sometimes mask
+          a real overrun, leaving the 8390 in a stopped state with rec'vr off. */
+       outb_p(ENISR_RX+ENISR_RX_ERR, e8390_base+EN0_ISR);
+       return;
+}
+
+/**
+ * ei_rx_overrun - handle receiver overrun
+ * @dev: network device which threw exception
+ *
+ * We have a receiver overrun: we have to kick the 8390 to get it started
+ * again. Problem is that you have to kick it exactly as NS prescribes in
+ * the updated datasheets, or "the NIC may act in an unpredictable manner."
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network."  Ugh.
+ * Called with lock held. Don't call this with the interrupts off or your
+ * computer will hate you - it takes 10ms or so. 
+ */
+
+static void ei_rx_overrun(struct net_device *dev)
+{
+       long e8390_base = dev->base_addr;
+       unsigned char was_txing, must_resend = 0;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+    
+       /*
+        * Record whether a Tx was in progress and then issue the
+        * stop command.
+        */
+       was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
+       outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+    
+       if (ei_debug > 1)
+               printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
+       ei_local->stat.rx_over_errors++;
+    
+       /* 
+        * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+        * Early datasheets said to poll the reset bit, but now they say that
+        * it "is not a reliable indicator and subsequently should be ignored."
+        * We wait at least 10ms.
+        */
+
+       udelay(10*1000);
+
+       /*
+        * Reset RBCR[01] back to zero as per magic incantation.
+        */
+       outb_p(0x00, e8390_base+EN0_RCNTLO);
+       outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+       /*
+        * See if any Tx was interrupted or not. According to NS, this
+        * step is vital, and skipping it will cause no end of havoc.
+        */
+
+       if (was_txing)
+       { 
+               unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+               if (!tx_completed)
+                       must_resend = 1;
+       }
+
+       /*
+        * Have to enter loopback mode and then restart the NIC before
+        * you are allowed to slurp packets up off the ring.
+        */
+       outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+       outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+       /*
+        * Clear the Rx ring of all the debris, and ack the interrupt.
+        */
+       ei_receive(dev);
+       outb_p(ENISR_OVER, e8390_base+EN0_ISR);
+
+       /*
+        * Leave loopback mode, and resend any packet that got stopped.
+        */
+       outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); 
+       if (must_resend)
+               outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+}
+
+/*
+ *     Collect the stats. This is called unlocked and from several contexts.
+ */
+static struct net_device_stats *get_stats(struct net_device *dev)
+{
+       long ioaddr = dev->base_addr;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       unsigned long flags;
+    
+       /* If the card is stopped, just return the present stats. */
+       if (!netif_running(dev))
+               return &ei_local->stat;
+
+       spin_lock_irqsave(&ei_local->page_lock,flags);
+       /* Read the counter registers, assuming we are in page 0. */
+       ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
+       ei_local->stat.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
+       ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+       spin_unlock_irqrestore(&ei_local->page_lock, flags);
+    
+       return &ei_local->stat;
+}
+
+/*
+ * Update the given Autodin II CRC value with another data byte.
+ */
+
+static inline u32 update_crc(u8 byte, u32 current_crc)
+{
+       int bit;
+       u8 ah = 0;
+       for (bit=0; bit<8; bit++) 
+       {
+               u8 carry = (current_crc>>31);
+               current_crc <<= 1;
+               ah = ((ah<<1) | carry) ^ byte;
+               if (ah&1)
+                       current_crc ^= 0x04C11DB7;      /* CRC polynomial */
+               ah >>= 1;
+               byte >>= 1;
+       }
+       return current_crc;
+}
+
+/*
+ * Form the 64 bit 8390 multicast table from the linked list of addresses
+ * associated with this dev structure.
+ */
+static inline void make_mc_bits(u8 *bits, struct net_device *dev)
+{
+       struct dev_mc_list *dmi;
+
+       for (dmi=dev->mc_list; dmi; dmi=dmi->next) 
+       {
+               int i;
+               u32 crc;
+               if (dmi->dmi_addrlen != ETH_ALEN) 
+               {
+                       printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
+                       continue;
+               }
+               crc = 0xffffffff;       /* initial CRC value */
+               for (i=0; i<ETH_ALEN; i++)
+                       crc = update_crc(dmi->dmi_addr[i], crc);
+               /* 
+                * The 8390 uses the 6 most significant bits of the
+                * CRC to index the multicast table.
+                */
+               bits[crc>>29] |= (1<<((crc>>26)&7));
+       }
+}
+
+/**
+ * do_set_multicast_list - set/clear multicast filter
+ * @dev: net device for which multicast filter is adjusted
+ *
+ *     Set or clear the multicast filter for this adaptor. May be called
+ *     from a BH in 2.1.x. Must be called with lock held. 
+ */
+static void do_set_multicast_list(struct net_device *dev)
+{
+       long e8390_base = dev->base_addr;
+       int i;
+       struct ei_device *ei_local = (struct ei_device*)dev->priv;
+
+       if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) 
+       {
+               memset(ei_local->mcfilter, 0, 8);
+               if (dev->mc_list)
+                       make_mc_bits(ei_local->mcfilter, dev);
+       }
+       else
+               memset(ei_local->mcfilter, 0xFF, 8);    /* mcast set to accept-all */
+
+       /* 
+        * DP8390 manuals don't specify any magic sequence for altering
+        * the multicast regs on an already running card. To be safe, we
+        * ensure multicast mode is off prior to loading up the new hash
+        * table. If this proves to be not enough, we can always resort
+        * to stopping the NIC, loading the table and then restarting.
+        *
+        * Bug Alert!  The MC regs on the SMC 83C690 (SMC Elite and SMC 
+        * Elite16) appear to be write-only. The NS 8390 data sheet lists
+        * them as r/w so this is a bug.  The SMC 83C790 (SMC Ultra and
+        * Ultra32 EISA) appears to have this bug fixed.
+        */
+        
+       if (netif_running(dev))
+               outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+       outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
+       for(i = 0; i < 8; i++) 
+       {
+               outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
+#ifndef BUG_83C690
+               if(inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
+                       printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
+#endif
+       }
+       outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
+
+       if(dev->flags&IFF_PROMISC)
+               outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+       else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
+               outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+       else
+               outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+ }
+
+/*
+ *     Called without lock held. This is invoked from user context and may
+ *     be parallel to just about everything else. Its also fairly quick and
+ *     not called too often. Must protect against both bh and irq users
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+       unsigned long flags;
+       struct ei_device *ei_local = (struct ei_device*)dev->priv;
+       
+       spin_lock_irqsave(&ei_local->page_lock, flags);
+       do_set_multicast_list(dev);
+       spin_unlock_irqrestore(&ei_local->page_lock, flags);
+}      
+
+/**
+ * ethdev_init - init rest of 8390 device struct
+ * @dev: network device structure to init
+ *
+ * Initialize the rest of the 8390 device structure.  Do NOT __init
+ * this, as it is used by 8390 based modular drivers too.
+ */
+
+int ethdev_init(struct net_device *dev)
+{
+       if (ei_debug > 1)
+               printk(version);
+    
+       if (dev->priv == NULL) 
+       {
+               struct ei_device *ei_local;
+               
+               dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+               if (dev->priv == NULL)
+                       return -ENOMEM;
+               memset(dev->priv, 0, sizeof(struct ei_device));
+               ei_local = (struct ei_device *)dev->priv;
+               spin_lock_init(&ei_local->page_lock);
+       }
+    
+       dev->hard_start_xmit = &ei_start_xmit;
+       dev->get_stats  = get_stats;
+       dev->set_multicast_list = &set_multicast_list;
+
+       ether_setup(dev);
+        
+       return 0;
+}
+\f
+
+
+/* This page of functions should be 8390 generic */
+/* Follow National Semi's recommendations for initializing the "NIC". */
+
+/**
+ * NS8390_init - initialize 8390 hardware
+ * @dev: network device to initialize
+ * @startp: boolean.  non-zero value to initiate chip processing
+ *
+ *     Must be called with lock held.
+ */
+
+void NS8390_init(struct net_device *dev, int startp)
+{
+       long e8390_base = dev->base_addr;
+       struct ei_device *ei_local = (struct ei_device *) dev->priv;
+       int i;
+       int endcfg = ei_local->word16
+           ? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
+           : 0x48;
+    
+       if(sizeof(struct e8390_pkt_hdr)!=4)
+               panic("8390.c: header struct mispacked\n");    
+       /* Follow National Semi's recommendations for initing the DP83902. */
+       outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
+       outb_p(endcfg, e8390_base + EN0_DCFG);  /* 0x48 or 0x49 */
+       /* Clear the remote byte count registers. */
+       outb_p(0x00,  e8390_base + EN0_RCNTLO);
+       outb_p(0x00,  e8390_base + EN0_RCNTHI);
+       /* Set to monitor and loopback mode -- this is vital!. */
+       outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+       outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
+       /* Set the transmit page and receive ring. */
+       outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
+       ei_local->tx1 = ei_local->tx2 = 0;
+       outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
+       outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY);       /* 3c503 says 0x3f,NS0x26*/
+       ei_local->current_page = ei_local->rx_start_page;               /* assert boundary+1 */
+       outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
+       /* Clear the pending interrupts and mask. */
+       outb_p(0xFF, e8390_base + EN0_ISR);
+       outb_p(0x00,  e8390_base + EN0_IMR);
+    
+       /* Copy the station address into the DS8390 registers. */
+
+       outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
+       for(i = 0; i < 6; i++) 
+       {
+               outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
+               if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
+                       printk(KERN_ERR "Hw. address read/write mismap %d\n",i);
+       }
+
+       outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+       outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+       netif_start_queue(dev);
+       ei_local->tx1 = ei_local->tx2 = 0;
+       ei_local->txing = 0;
+
+       if (startp) 
+       {
+               outb_p(0xff,  e8390_base + EN0_ISR);
+               outb_p(ENISR_ALL,  e8390_base + EN0_IMR);
+               outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base+E8390_CMD);
+               outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+               /* 3c503 TechMan says rxconfig only after the NIC is started. */
+               outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
+               do_set_multicast_list(dev);     /* (re)load the mcast table */
+       }
+}
+
+/* Trigger a transmit start, assuming the length is valid. 
+   Always called with the page lock held */
+   
+static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
+                                                               int start_page)
+{
+       long e8390_base = dev->base_addr;
+       struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) dev->priv;
+   
+       outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
+    
+       if (inb_p(e8390_base) & E8390_TRANS) 
+       {
+               printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
+                       dev->name);
+               return;
+       }
+       outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
+       outb_p(length >> 8, e8390_base + EN0_TCNTHI);
+       outb_p(start_page, e8390_base + EN0_TPSR);
+       outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base+E8390_CMD);
+}
+
+EXPORT_SYMBOL(ei_open);
+EXPORT_SYMBOL(ei_close);
+EXPORT_SYMBOL(ei_interrupt);
+EXPORT_SYMBOL(ei_tx_timeout);
+EXPORT_SYMBOL(ethdev_init);
+EXPORT_SYMBOL(NS8390_init);
+
+#if defined(MODULE)
+
+int init_module(void)
+{
+       return 0;
+}
+
+void cleanup_module(void)
+{
+}
+
+#endif /* MODULE */
diff --git a/xen-2.4.16/drivers/net/ne/8390.h b/xen-2.4.16/drivers/net/ne/8390.h
new file mode 100644 (file)
index 0000000..1a3be17
--- /dev/null
@@ -0,0 +1,197 @@
+/* Generic NS8390 register definitions. */
+/* This file is part of Donald Becker's 8390 drivers, and is distributed
+   under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
+   Some of these names and comments originated from the Crynwr
+   packet drivers, which are distributed under the GPL. */
+
+#ifndef _8390_h
+#define _8390_h
+
+#include <xeno/config.h>
+#include <xeno/if_ether.h>
+#include <xeno/ioport.h>
+#include <xeno/skbuff.h>
+
+#define TX_2X_PAGES 12
+#define TX_1X_PAGES 6
+
+/* Should always use two Tx slots to get back-to-back transmits. */
+#define EI_PINGPONG
+
+#ifdef EI_PINGPONG
+#define TX_PAGES TX_2X_PAGES
+#else
+#define TX_PAGES TX_1X_PAGES
+#endif
+
+#define ETHER_ADDR_LEN 6
+
+/* The 8390 specific per-packet-header format. */
+struct e8390_pkt_hdr {
+  unsigned char status; /* status */
+  unsigned char next;   /* pointer to next packet. */
+  unsigned short count; /* header + packet length in bytes */
+};
+
+#ifdef notdef
+extern int ei_debug;
+#else
+#define ei_debug 1
+#endif
+
+#ifndef HAVE_AUTOIRQ
+/* From auto_irq.c */
+extern void autoirq_setup(int waittime);
+extern unsigned long autoirq_report(int waittime);
+#endif
+
+extern int ethdev_init(struct net_device *dev);
+extern void NS8390_init(struct net_device *dev, int startp);
+extern int ei_open(struct net_device *dev);
+extern int ei_close(struct net_device *dev);
+extern void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+/* Most of these entries should be in 'struct net_device' (or most of the
+   things in there should be here!) */
+/* You have one of these per-board */
+struct ei_device {
+       const char *name;
+       void (*reset_8390)(struct net_device *);
+       void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
+       void (*block_output)(struct net_device *, int, const unsigned char *, int);
+       void (*block_input)(struct net_device *, int, struct sk_buff *, int);
+       unsigned char mcfilter[8];
+       unsigned open:1;
+       unsigned word16:1;              /* We have the 16-bit (vs 8-bit) version of the card. */
+       unsigned bigendian:1;           /* 16-bit big endian mode. Do NOT */
+                                       /* set this on random 8390 clones! */
+       unsigned txing:1;               /* Transmit Active */
+       unsigned irqlock:1;             /* 8390's intrs disabled when '1'. */
+       unsigned dmaing:1;              /* Remote DMA Active */
+       unsigned char tx_start_page, rx_start_page, stop_page;
+       unsigned char current_page;     /* Read pointer in buffer  */
+       unsigned char interface_num;    /* Net port (AUI, 10bT.) to use. */
+       unsigned char txqueue;          /* Tx Packet buffer queue length. */
+       short tx1, tx2;                 /* Packet lengths for ping-pong tx. */
+       short lasttx;                   /* Alpha version consistency check. */
+       unsigned char reg0;             /* Register '0' in a WD8013 */
+       unsigned char reg5;             /* Register '5' in a WD8013 */
+       unsigned char saved_irq;        /* Original dev->irq value. */
+       struct net_device_stats stat;   /* The new statistics table. */
+       u32 *reg_offset;                /* Register mapping table */
+       spinlock_t page_lock;           /* Page register locks */
+       unsigned long priv;             /* Private field to store bus IDs etc. */
+};
+
+/* The maximum number of 8390 interrupt service routines called per IRQ. */
+#define MAX_SERVICE 12
+
+/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */
+#define TX_TIMEOUT (20*HZ/100)
+
+#define ei_status (*(struct ei_device *)(dev->priv))
+
+/* Some generic ethernet register configurations. */
+#define E8390_TX_IRQ_MASK      0xa     /* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK      0x5
+#define E8390_RXCONFIG         0x4     /* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF            0x20    /* EN0_RXCR: Accept no packets */
+#define E8390_TXCONFIG         0x00    /* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF            0x02    /* EN0_TXCR: Transmitter off */
+
+/*  Register accessed at EN_CMD, the 8390 base addr.  */
+#define E8390_STOP     0x01    /* Stop and reset the chip */
+#define E8390_START    0x02    /* Start the chip, clear reset */
+#define E8390_TRANS    0x04    /* Transmit a frame */
+#define E8390_RREAD    0x08    /* Remote read */
+#define E8390_RWRITE   0x10    /* Remote write  */
+#define E8390_NODMA    0x20    /* Remote DMA */
+#define E8390_PAGE0    0x00    /* Select page chip registers */
+#define E8390_PAGE1    0x40    /* using the two high-order bits */
+#define E8390_PAGE2    0x80    /* Page 3 is invalid. */
+
+/*
+ *     Only generate indirect loads given a machine that needs them.
+ */
+#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
+    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
+    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE) || \
+    defined(CONFIG_ARM_ETHERH) || defined(CONFIG_ARM_ETHERH_MODULE)
+#define EI_SHIFT(x)    (ei_local->reg_offset[x])
+#else
+#define EI_SHIFT(x)    (x)
+#endif
+
+#define E8390_CMD      EI_SHIFT(0x00)  /* The command register (for all pages) */
+/* Page 0 register offsets. */
+#define EN0_CLDALO     EI_SHIFT(0x01)  /* Low byte of current local dma addr  RD */
+#define EN0_STARTPG    EI_SHIFT(0x01)  /* Starting page of ring bfr WR */
+#define EN0_CLDAHI     EI_SHIFT(0x02)  /* High byte of current local dma addr  RD */
+#define EN0_STOPPG     EI_SHIFT(0x02)  /* Ending page +1 of ring bfr WR */
+#define EN0_BOUNDARY   EI_SHIFT(0x03)  /* Boundary page of ring bfr RD WR */
+#define EN0_TSR                EI_SHIFT(0x04)  /* Transmit status reg RD */
+#define EN0_TPSR       EI_SHIFT(0x04)  /* Transmit starting page WR */
+#define EN0_NCR                EI_SHIFT(0x05)  /* Number of collision reg RD */
+#define EN0_TCNTLO     EI_SHIFT(0x05)  /* Low  byte of tx byte count WR */
+#define EN0_FIFO       EI_SHIFT(0x06)  /* FIFO RD */
+#define EN0_TCNTHI     EI_SHIFT(0x06)  /* High byte of tx byte count WR */
+#define EN0_ISR                EI_SHIFT(0x07)  /* Interrupt status reg RD WR */
+#define EN0_CRDALO     EI_SHIFT(0x08)  /* low byte of current remote dma address RD */
+#define EN0_RSARLO     EI_SHIFT(0x08)  /* Remote start address reg 0 */
+#define EN0_CRDAHI     EI_SHIFT(0x09)  /* high byte, current remote dma address RD */
+#define EN0_RSARHI     EI_SHIFT(0x09)  /* Remote start address reg 1 */
+#define EN0_RCNTLO     EI_SHIFT(0x0a)  /* Remote byte count reg WR */
+#define EN0_RCNTHI     EI_SHIFT(0x0b)  /* Remote byte count reg WR */
+#define EN0_RSR                EI_SHIFT(0x0c)  /* rx status reg RD */
+#define EN0_RXCR       EI_SHIFT(0x0c)  /* RX configuration reg WR */
+#define EN0_TXCR       EI_SHIFT(0x0d)  /* TX configuration reg WR */
+#define EN0_COUNTER0   EI_SHIFT(0x0d)  /* Rcv alignment error counter RD */
+#define EN0_DCFG       EI_SHIFT(0x0e)  /* Data configuration reg WR */
+#define EN0_COUNTER1   EI_SHIFT(0x0e)  /* Rcv CRC error counter RD */
+#define EN0_IMR                EI_SHIFT(0x0f)  /* Interrupt mask reg WR */
+#define EN0_COUNTER2   EI_SHIFT(0x0f)  /* Rcv missed frame error counter RD */
+
+/* Bits in EN0_ISR - Interrupt status register */
+#define ENISR_RX       0x01    /* Receiver, no error */
+#define ENISR_TX       0x02    /* Transmitter, no error */
+#define ENISR_RX_ERR   0x04    /* Receiver, with error */
+#define ENISR_TX_ERR   0x08    /* Transmitter, with error */
+#define ENISR_OVER     0x10    /* Receiver overwrote the ring */
+#define ENISR_COUNTERS 0x20    /* Counters need emptying */
+#define ENISR_RDC      0x40    /* remote dma complete */
+#define ENISR_RESET    0x80    /* Reset completed */
+#define ENISR_ALL      0x3f    /* Interrupts we will enable */
+
+/* Bits in EN0_DCFG - Data config register */
+#define ENDCFG_WTS     0x01    /* word transfer mode selection */
+#define ENDCFG_BOS     0x02    /* byte order selection */
+
+/* Page 1 register offsets. */
+#define EN1_PHYS   EI_SHIFT(0x01)      /* This board's physical enet addr RD WR */
+#define EN1_PHYS_SHIFT(i)  EI_SHIFT(i+1) /* Get and set mac address */
+#define EN1_CURPAG EI_SHIFT(0x07)      /* Current memory page RD WR */
+#define EN1_MULT   EI_SHIFT(0x08)      /* Multicast filter mask array (8 bytes) RD WR */
+#define EN1_MULT_SHIFT(i)  EI_SHIFT(8+i) /* Get and set multicast filter */
+
+/* Bits in received packet status byte and EN0_RSR*/
+#define ENRSR_RXOK     0x01    /* Received a good packet */
+#define ENRSR_CRC      0x02    /* CRC error */
+#define ENRSR_FAE      0x04    /* frame alignment error */
+#define ENRSR_FO       0x08    /* FIFO overrun */
+#define ENRSR_MPA      0x10    /* missed pkt */
+#define ENRSR_PHY      0x20    /* physical/multicast address */
+#define ENRSR_DIS      0x40    /* receiver disable. set in monitor mode */
+#define ENRSR_DEF      0x80    /* deferring */
+
+/* Transmitted packet status, EN0_TSR. */
+#define ENTSR_PTX 0x01 /* Packet transmitted without error */
+#define ENTSR_ND  0x02 /* The transmit wasn't deferred. */
+#define ENTSR_COL 0x04 /* The transmit collided at least once. */
+#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
+#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
+#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
+#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
+#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
+
+#endif /* _8390_h */
diff --git a/xen-2.4.16/drivers/net/ne/Makefile b/xen-2.4.16/drivers/net/ne/Makefile
new file mode 100644 (file)
index 0000000..d1bcc12
--- /dev/null
@@ -0,0 +1,8 @@
+
+include $(BASEDIR)/Rules.mk
+
+default: $(OBJS)
+       $(LD) -r -o ne_drv.o $(OBJS)
+
+clean:
+       rm -f *.o *~ core
diff --git a/xen-2.4.16/drivers/net/ne/ne.c b/xen-2.4.16/drivers/net/ne/ne.c
new file mode 100644 (file)
index 0000000..f694fc1
--- /dev/null
@@ -0,0 +1,685 @@
+/* ne.c: A general non-shared-memory NS8390 ethernet driver for linux. */
+/*
+    Written 1992-94 by Donald Becker.
+
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.
+
+    This software may be used and distributed according to the terms
+    of the GNU General Public License, incorporated herein by reference.
+
+    The author may be reached as becker@scyld.com, or C/O
+    Scyld Computing Corporation, 410 Severn Ave., Suite 210, Annapolis MD 21403
+
+    This driver should work with many programmed-I/O 8390-based ethernet
+    boards.  Currently it supports the NE1000, NE2000, many clones,
+    and some Cabletron products.
+
+    Changelog:
+
+    Paul Gortmaker     : use ENISR_RDC to monitor Tx PIO uploads, made
+                         sanity checks and bad clone support optional.
+    Paul Gortmaker     : new reset code, reset card after probe at boot.
+    Paul Gortmaker     : multiple card support for module users.
+    Paul Gortmaker     : Support for PCI ne2k clones, similar to lance.c
+    Paul Gortmaker     : Allow users with bad cards to avoid full probe.
+    Paul Gortmaker     : PCI probe changes, more PCI cards supported.
+    rjohnson@analogic.com : Changed init order so an interrupt will only
+    occur after memory is allocated for dev->priv. Deallocated memory
+    last in cleanup_modue()
+    Richard Guenther    : Added support for ISAPnP cards
+    Paul Gortmaker     : Discontinued PCI support - use ne2k-pci.c instead.
+
+*/
+
+/* Routines for the NatSemi-based designs (NE[12]000). */
+
+static const char version1[] =
+"ne.c:v1.10 9/23/94 Donald Becker (becker@scyld.com)\n";
+static const char version2[] =
+"Last modified Nov 1, 2000 by Paul Gortmaker\n";
+
+
+#include <xeno/module.h>
+#include <xeno/kernel.h>
+#include <xeno/sched.h>
+#include <xeno/errno.h>
+#include <xeno/init.h>
+#include <xeno/delay.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <xeno/netdevice.h>
+#include <xeno/etherdevice.h>
+#include "8390.h"
+
+/* Some defines that people can play with if so inclined. */
+
+/* Do we support clones that don't adhere to 14,15 of the SAprom ? */
+#define SUPPORT_NE_BAD_CLONES
+
+/* Do we perform extra sanity checks on stuff ? */
+/* #define NE_SANITY_CHECK */
+
+/* Do we implement the read before write bugfix ? */
+/* #define NE_RW_BUGFIX */
+
+/* Do we have a non std. amount of memory? (in units of 256 byte pages) */
+/* #define PACKETBUF_MEMSIZE   0x40 */
+
+#ifdef SUPPORT_NE_BAD_CLONES
+/* A list of bad clones that we none-the-less recognize. */
+static struct { const char *name8, *name16; unsigned char SAprefix[4];}
+bad_clone_list[] __initdata = {
+    {"DE100", "DE200", {0x00, 0xDE, 0x01,}},
+    {"DE120", "DE220", {0x00, 0x80, 0xc8,}},
+    {"DFI1000", "DFI2000", {'D', 'F', 'I',}}, /* Original, eh?  */
+    {"EtherNext UTP8", "EtherNext UTP16", {0x00, 0x00, 0x79}},
+    {"NE1000","NE2000-invalid", {0x00, 0x00, 0xd8}}, /* Ancient real NE1000. */
+    {"NN1000", "NN2000",  {0x08, 0x03, 0x08}}, /* Outlaw no-name clone. */
+    {"4-DIM8","4-DIM16", {0x00,0x00,0x4d,}},  /* Outlaw 4-Dimension cards. */
+    {"Con-Intl_8", "Con-Intl_16", {0x00, 0x00, 0x24}}, /* Connect Int'nl */
+    {"ET-100","ET-200", {0x00, 0x45, 0x54}}, /* YANG and YA clone */
+    {"COMPEX","COMPEX16",{0x00,0x80,0x48}}, /* Broken ISA Compex cards */
+    {"E-LAN100", "E-LAN200", {0x00, 0x00, 0x5d}}, /* Broken ne1000 clones */
+    {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */
+    {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */
+    {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */
+    {0,}
+};
+#endif
+
+/* ---- No user-serviceable parts below ---- */
+
+#define NE_BASE         (dev->base_addr)
+#define NE_CMD         0x00
+#define NE_DATAPORT    0x10    /* NatSemi-defined port window offset. */
+#define NE_RESET       0x1f    /* Issue a read to reset, a write to clear. */
+#define NE_IO_EXTENT   0x20
+
+#define NE1SM_START_PG 0x20    /* First page of TX buffer */
+#define NE1SM_STOP_PG  0x40    /* Last page +1 of RX ring */
+#define NESM_START_PG  0x40    /* First page of TX buffer */
+#define NESM_STOP_PG   0x80    /* Last page +1 of RX ring */
+
+int ne_probe(struct net_device *dev);
+static int ne_probe1(struct net_device *dev, int ioaddr);
+
+static int ne_open(struct net_device *dev);
+static int ne_close(struct net_device *dev);
+
+static void ne_reset_8390(struct net_device *dev);
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+                         int ring_page);
+static void ne_block_input(struct net_device *dev, int count,
+                         struct sk_buff *skb, int ring_offset);
+static void ne_block_output(struct net_device *dev, const int count,
+               const unsigned char *buf, const int start_page);
+
+\f
+/*  Probe for various non-shared-memory ethercards.
+
+   NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
+   buffer memory space.  NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of
+   the SAPROM, while other supposed NE2000 clones must be detected by their
+   SA prefix.
+
+   Reading the SAPROM from a word-wide card with the 8390 set in byte-wide
+   mode results in doubled values, which can be detected and compensated for.
+
+   The probe is also responsible for initializing the card and filling
+   in the 'dev' and 'ei_status' structures.
+
+   We use the minimum memory size for some ethercard product lines, iff we can't
+   distinguish models.  You can increase the packet buffer size by setting
+   PACKETBUF_MEMSIZE.  Reported Cabletron packet buffer locations are:
+       E1010   starts at 0x100 and ends at 0x2000.
+       E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory")
+       E2010    starts at 0x100 and ends at 0x4000.
+       E2010-x starts at 0x100 and ends at 0xffff.  */
+
+int __init ne_probe(struct net_device *dev)
+{
+       unsigned int base_addr = dev->base_addr;
+
+       SET_MODULE_OWNER(dev);
+
+       /* First check any supplied i/o locations. User knows best. <cough> */
+       if (base_addr > 0x1ff)  /* Check a single specified location. */
+               return ne_probe1(dev, base_addr);
+
+       return -ENODEV;
+}
+
+static int __init ne_probe1(struct net_device *dev, int ioaddr)
+{
+       int i;
+       unsigned char SA_prom[32];
+       int wordlength = 2;
+       const char *name = NULL;
+       int start_page, stop_page;
+       int neX000, ctron, copam, bad_card;
+       int reg0, ret;
+       static unsigned version_printed;
+
+       if (!request_region(ioaddr, NE_IO_EXTENT, dev->name))
+               return -EBUSY;
+
+       reg0 = inb_p(ioaddr);
+       if (reg0 == 0xFF) {
+               ret = -ENODEV;
+               goto err_out;
+       }
+
+       /* Do a preliminary verification that we have a 8390. */
+       {
+               int regd;
+               outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
+               regd = inb_p(ioaddr + 0x0d);
+               outb_p(0xff, ioaddr + 0x0d);
+               outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
+               inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
+               if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
+                       outb_p(reg0, ioaddr);
+                       outb_p(regd, ioaddr + 0x0d);    /* Restore the old values. */
+                       ret = -ENODEV;
+                       goto err_out;
+               }
+       }
+
+       if (ei_debug  &&  version_printed++ == 0)
+               printk(KERN_INFO "%s" KERN_INFO "%s", version1, version2);
+
+       printk(KERN_INFO "NE*000 ethercard probe at %#3x:", ioaddr);
+
+       /* A user with a poor card that fails to ack the reset, or that
+          does not have a valid 0x57,0x57 signature can still use this
+          without having to recompile. Specifying an i/o address along
+          with an otherwise unused dev->mem_end value of "0xBAD" will
+          cause the driver to skip these parts of the probe. */
+
+       bad_card = ((dev->base_addr != 0) && (dev->mem_end == 0xbad));
+
+       /* Reset card. Who knows what dain-bramaged state it was left in. */
+
+       {
+               unsigned long reset_start_time = jiffies;
+
+               /* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+               outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET);
+
+               while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
+               if (jiffies - reset_start_time > 2*HZ/100) {
+                       if (bad_card) {
+                               printk(" (warning: no reset ack)");
+                               break;
+                       } else {
+                               printk(" not found (no reset ack).\n");
+                               ret = -ENODEV;
+                               goto err_out;
+                       }
+               }
+
+               outb_p(0xff, ioaddr + EN0_ISR);         /* Ack all intr. */
+       }
+
+       /* Read the 16 bytes of station address PROM.
+          We must first initialize registers, similar to NS8390_init(eifdev, 0).
+          We can't reliably read the SAPROM address without this.
+          (I learned the hard way!). */
+       {
+               struct {unsigned char value, offset; } program_seq[] =
+               {
+                       {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+                       {0x48,  EN0_DCFG},      /* Set byte-wide (0x48) access. */
+                       {0x00,  EN0_RCNTLO},    /* Clear the count regs. */
+                       {0x00,  EN0_RCNTHI},
+                       {0x00,  EN0_IMR},       /* Mask completion irq. */
+                       {0xFF,  EN0_ISR},
+                       {E8390_RXOFF, EN0_RXCR},        /* 0x20  Set to monitor */
+                       {E8390_TXOFF, EN0_TXCR},        /* 0x02  and loopback mode. */
+                       {32,    EN0_RCNTLO},
+                       {0x00,  EN0_RCNTHI},
+                       {0x00,  EN0_RSARLO},    /* DMA starting at 0x0000. */
+                       {0x00,  EN0_RSARHI},
+                       {E8390_RREAD+E8390_START, E8390_CMD},
+               };
+
+               for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+                       outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+       }
+       for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
+               SA_prom[i] = inb(ioaddr + NE_DATAPORT);
+               SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
+               if (SA_prom[i] != SA_prom[i+1])
+                       wordlength = 1;
+       }
+
+       if (wordlength == 2)
+       {
+               for (i = 0; i < 16; i++)
+                       SA_prom[i] = SA_prom[i+i];
+               /* We must set the 8390 for word mode. */
+               outb_p(0x49, ioaddr + EN0_DCFG);
+               start_page = NESM_START_PG;
+               stop_page = NESM_STOP_PG;
+       } else {
+               start_page = NE1SM_START_PG;
+               stop_page = NE1SM_STOP_PG;
+       }
+
+       neX000 = (SA_prom[14] == 0x57  &&  SA_prom[15] == 0x57);
+       ctron =  (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d);
+       copam =  (SA_prom[14] == 0x49 && SA_prom[15] == 0x00);
+
+       /* Set up the rest of the parameters. */
+       if (neX000 || bad_card || copam) {
+               name = (wordlength == 2) ? "NE2000" : "NE1000";
+       }
+       else if (ctron)
+       {
+               name = (wordlength == 2) ? "Ctron-8" : "Ctron-16";
+               start_page = 0x01;
+               stop_page = (wordlength == 2) ? 0x40 : 0x20;
+       }
+       else
+       {
+#ifdef SUPPORT_NE_BAD_CLONES
+               /* Ack!  Well, there might be a *bad* NE*000 clone there.
+                  Check for total bogus addresses. */
+               for (i = 0; bad_clone_list[i].name8; i++)
+               {
+                       if (SA_prom[0] == bad_clone_list[i].SAprefix[0] &&
+                               SA_prom[1] == bad_clone_list[i].SAprefix[1] &&
+                               SA_prom[2] == bad_clone_list[i].SAprefix[2])
+                       {
+                               if (wordlength == 2)
+                               {
+                                       name = bad_clone_list[i].name16;
+                               } else {
+                                       name = bad_clone_list[i].name8;
+                               }
+                               break;
+                       }
+               }
+               if (bad_clone_list[i].name8 == NULL)
+               {
+                       printk(" not found (invalid signature %2.2x %2.2x).\n",
+                               SA_prom[14], SA_prom[15]);
+                       ret = -ENXIO;
+                       goto err_out;
+               }
+#else
+               printk(" not found.\n");
+               ret = -ENXIO;
+               goto err_out;
+#endif
+       }
+
+       if (dev->irq < 2)
+       {
+               unsigned long cookie = probe_irq_on();
+               outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */
+               outb_p(0x00, ioaddr + EN0_RCNTLO);
+               outb_p(0x00, ioaddr + EN0_RCNTHI);
+               outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
+               mdelay(10);             /* wait 10ms for interrupt to propagate */
+               outb_p(0x00, ioaddr + EN0_IMR);                 /* Mask it again. */
+               dev->irq = probe_irq_off(cookie);
+               if (ei_debug > 2)
+                       printk(" autoirq is %d\n", dev->irq);
+       } else if (dev->irq == 2)
+               /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+                  or don't know which one to set. */
+               dev->irq = 9;
+
+       if (! dev->irq) {
+               printk(" failed to detect IRQ line.\n");
+               ret = -EAGAIN;
+               goto err_out;
+       }
+
+       /* Allocate dev->priv and fill in 8390 specific dev fields. */
+       if (ethdev_init(dev))
+       {
+               printk (" unable to get memory for dev->priv.\n");
+               ret = -ENOMEM;
+               goto err_out;
+       }
+
+       /* Snarf the interrupt now.  There's no point in waiting since we cannot
+          share and the board will usually be enabled. */
+       ret = request_irq(dev->irq, ei_interrupt, 0, name, dev);
+       if (ret) {
+               printk (" unable to get IRQ %d (errno=%d).\n", dev->irq, ret);
+               goto err_out_kfree;
+       }
+
+       dev->base_addr = ioaddr;
+
+       for(i = 0; i < ETHER_ADDR_LEN; i++) {
+               printk(" %2.2x", SA_prom[i]);
+               dev->dev_addr[i] = SA_prom[i];
+       }
+
+       printk("\n%s: %s found at %#x, using IRQ %d.\n",
+               dev->name, name, ioaddr, dev->irq);
+
+       ei_status.name = name;
+       ei_status.tx_start_page = start_page;
+       ei_status.stop_page = stop_page;
+       ei_status.word16 = (wordlength == 2);
+
+       ei_status.rx_start_page = start_page + TX_PAGES;
+#ifdef PACKETBUF_MEMSIZE
+        /* Allow the packet buffer size to be overridden by know-it-alls. */
+       ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE;
+#endif
+
+       ei_status.reset_8390 = &ne_reset_8390;
+       ei_status.block_input = &ne_block_input;
+       ei_status.block_output = &ne_block_output;
+       ei_status.get_8390_hdr = &ne_get_8390_hdr;
+       ei_status.priv = 0;
+       dev->open = &ne_open;
+       dev->stop = &ne_close;
+       NS8390_init(dev, 0);
+       return 0;
+
+err_out_kfree:
+       kfree(dev->priv);
+       dev->priv = NULL;
+err_out:
+       release_region(ioaddr, NE_IO_EXTENT);
+       return ret;
+}
+
+static int ne_open(struct net_device *dev)
+{
+       ei_open(dev);
+       return 0;
+}
+
+static int ne_close(struct net_device *dev)
+{
+       if (ei_debug > 1)
+               printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
+       ei_close(dev);
+       return 0;
+}
+
+/* Hard reset the card.  This used to pause for the same period that a
+   8390 reset command required, but that shouldn't be necessary. */
+
+static void ne_reset_8390(struct net_device *dev)
+{
+       unsigned long reset_start_time = jiffies;
+
+       if (ei_debug > 1)
+               printk(KERN_DEBUG "resetting the 8390 t=%ld...", jiffies);
+
+       /* DON'T change these to inb_p/outb_p or reset will fail on clones. */
+       outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET);
+
+       ei_status.txing = 0;
+       ei_status.dmaing = 0;
+
+       /* This check _should_not_ be necessary, omit eventually. */
+       while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
+               if (jiffies - reset_start_time > 2*HZ/100) {
+                       printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name);
+                       break;
+               }
+       outb_p(ENISR_RESET, NE_BASE + EN0_ISR); /* Ack intr. */
+}
+
+/* Grab the 8390 specific header. Similar to the block_input routine, but
+   we don't need to be concerned with ring wrap as the header will be at
+   the start of a page, so we optimize accordingly. */
+
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+       int nic_base = dev->base_addr;
+
+       /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+
+       if (ei_status.dmaing)
+       {
+               printk(KERN_EMERG "%s: DMAing conflict in ne_get_8390_hdr "
+                       "[DMAstat:%d][irqlock:%d].\n",
+                       dev->name, ei_status.dmaing, ei_status.irqlock);
+               return;
+       }
+
+       ei_status.dmaing |= 0x01;
+       outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+       outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+       outb_p(0, nic_base + EN0_RCNTHI);
+       outb_p(0, nic_base + EN0_RSARLO);               /* On page boundary */
+       outb_p(ring_page, nic_base + EN0_RSARHI);
+       outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+
+       if (ei_status.word16)
+               insw(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
+       else
+               insb(NE_BASE + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
+
+       outb_p(ENISR_RDC, nic_base + EN0_ISR);  /* Ack intr. */
+       ei_status.dmaing &= ~0x01;
+
+       le16_to_cpus(&hdr->count);
+}
+
+/* Block input and output, similar to the Crynwr packet driver.  If you
+   are porting to a new ethercard, look at the packet driver source for hints.
+   The NEx000 doesn't share the on-board packet memory -- you have to put
+   the packet out through the "remote DMA" dataport using outb. */
+
+static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+#ifdef NE_SANITY_CHECK
+       int xfer_count = count;
+#endif
+       int nic_base = dev->base_addr;
+       char *buf = skb->data;
+
+       /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+       if (ei_status.dmaing)
+       {
+               printk(KERN_EMERG "%s: DMAing conflict in ne_block_input "
+                       "[DMAstat:%d][irqlock:%d].\n",
+                       dev->name, ei_status.dmaing, ei_status.irqlock);
+               return;
+       }
+       ei_status.dmaing |= 0x01;
+       outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD);
+       outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+       outb_p(count >> 8, nic_base + EN0_RCNTHI);
+       outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+       outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+       outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+       if (ei_status.word16)
+       {
+               insw(NE_BASE + NE_DATAPORT,buf,count>>1);
+               if (count & 0x01)
+               {
+                       buf[count-1] = inb(NE_BASE + NE_DATAPORT);
+#ifdef NE_SANITY_CHECK
+                       xfer_count++;
+#endif
+               }
+       } else {
+               insb(NE_BASE + NE_DATAPORT, buf, count);
+       }
+
+#ifdef NE_SANITY_CHECK
+       /* This was for the ALPHA version only, but enough people have
+          been encountering problems so it is still here.  If you see
+          this message you either 1) have a slightly incompatible clone
+          or 2) have noise/speed problems with your bus. */
+
+       if (ei_debug > 1)
+       {
+               /* DMA termination address check... */
+               int addr, tries = 20;
+               do {
+                       /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
+                          -- it's broken for Rx on some cards! */
+                       int high = inb_p(nic_base + EN0_RSARHI);
+                       int low = inb_p(nic_base + EN0_RSARLO);
+                       addr = (high << 8) + low;
+                       if (((ring_offset + xfer_count) & 0xff) == low)
+                               break;
+               } while (--tries > 0);
+               if (tries <= 0)
+                       printk(KERN_WARNING "%s: RX transfer address mismatch,"
+                               "%#4.4x (expected) vs. %#4.4x (actual).\n",
+                               dev->name, ring_offset + xfer_count, addr);
+       }
+#endif
+       outb_p(ENISR_RDC, nic_base + EN0_ISR);  /* Ack intr. */
+       ei_status.dmaing &= ~0x01;
+}
+
+static void ne_block_output(struct net_device *dev, int count,
+               const unsigned char *buf, const int start_page)
+{
+       int nic_base = NE_BASE;
+       unsigned long dma_start;
+#ifdef NE_SANITY_CHECK
+       int retries = 0;
+#endif
+
+       /* Round the count up for word writes.  Do we need to do this?
+          What effect will an odd byte count have on the 8390?
+          I should check someday. */
+
+       if (ei_status.word16 && (count & 0x01))
+               count++;
+
+       /* This *shouldn't* happen. If it does, it's the last thing you'll see */
+       if (ei_status.dmaing)
+       {
+               printk(KERN_EMERG "%s: DMAing conflict in ne_block_output."
+                       "[DMAstat:%d][irqlock:%d]\n",
+                       dev->name, ei_status.dmaing, ei_status.irqlock);
+               return;
+       }
+       ei_status.dmaing |= 0x01;
+       /* We should already be in page 0, but to be safe... */
+       outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD);
+
+#ifdef NE_SANITY_CHECK
+retry:
+#endif
+
+#ifdef NE8390_RW_BUGFIX
+       /* Handle the read-before-write bug the same way as the
+          Crynwr packet driver -- the NatSemi method doesn't work.
+          Actually this doesn't always work either, but if you have
+          problems with your NEx000 this is better than nothing! */
+
+       outb_p(0x42, nic_base + EN0_RCNTLO);
+       outb_p(0x00,   nic_base + EN0_RCNTHI);
+       outb_p(0x42, nic_base + EN0_RSARLO);
+       outb_p(0x00, nic_base + EN0_RSARHI);
+       outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
+       /* Make certain that the dummy read has occurred. */
+       udelay(6);
+#endif
+
+       outb_p(ENISR_RDC, nic_base + EN0_ISR);
+
+       /* Now the normal output. */
+       outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+       outb_p(count >> 8,   nic_base + EN0_RCNTHI);
+       outb_p(0x00, nic_base + EN0_RSARLO);
+       outb_p(start_page, nic_base + EN0_RSARHI);
+
+       outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
+       if (ei_status.word16) {
+               outsw(NE_BASE + NE_DATAPORT, buf, count>>1);
+       } else {
+               outsb(NE_BASE + NE_DATAPORT, buf, count);
+       }
+
+       dma_start = jiffies;
+
+#ifdef NE_SANITY_CHECK
+       /* This was for the ALPHA version only, but enough people have
+          been encountering problems so it is still here. */
+
+       if (ei_debug > 1)
+       {
+               /* DMA termination address check... */
+               int addr, tries = 20;
+               do {
+                       int high = inb_p(nic_base + EN0_RSARHI);
+                       int low = inb_p(nic_base + EN0_RSARLO);
+                       addr = (high << 8) + low;
+                       if ((start_page << 8) + count == addr)
+                               break;
+               } while (--tries > 0);
+
+               if (tries <= 0)
+               {
+                       printk(KERN_WARNING "%s: Tx packet transfer address mismatch,"
+                               "%#4.4x (expected) vs. %#4.4x (actual).\n",
+                               dev->name, (start_page << 8) + count, addr);
+                       if (retries++ == 0)
+                               goto retry;
+               }
+       }
+#endif
+
+       while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+               if (jiffies - dma_start > 2*HZ/100) {           /* 20ms */
+                       printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name);
+                       ne_reset_8390(dev);
+                       NS8390_init(dev,1);
+                       break;
+               }
+
+       outb_p(ENISR_RDC, nic_base + EN0_ISR);  /* Ack intr. */
+       ei_status.dmaing &= ~0x01;
+       return;
+}
+
+static struct net_device dev_ne;
+
+static int __init init_module(void)
+{
+    struct net_device *dev = &dev_ne;
+    extern unsigned int opt_ne_base;
+
+    if ( opt_ne_base == 0 ) return 0;
+
+    dev->irq = 0;
+    dev->mem_end = 0;
+    dev->base_addr = opt_ne_base;
+    dev->init = ne_probe;
+
+    if ( register_netdev(dev) != 0 )
+    {
+        printk(KERN_WARNING "ne.c: No card found at io %#x\n", opt_ne_base);
+    }
+
+    return 0;
+}
+
+static void __exit cleanup_module(void)
+{
+    struct net_device *dev = &dev_ne;
+    if ( dev->priv != NULL )
+    {
+        void *priv = dev->priv;
+        free_irq(dev->irq, dev);
+        release_region(dev->base_addr, NE_IO_EXTENT);
+        unregister_netdev(dev);
+        kfree(priv);
+    }
+}
+
+module_init(init_module);
+module_exit(cleanup_module);
index 54fcf6f83f9714266a7331182f253703e93d251e..637281f64bf2efe77fce3f8eb2dd321748b638b8 100644 (file)
@@ -7,6 +7,8 @@
 #ifndef __XENO_CONFIG_H__
 #define __XENO_CONFIG_H__
 
+#define CONFIG_X86 1
+
 #define CONFIG_SMP 1
 #define CONFIG_X86_LOCAL_APIC 1
 #define CONFIG_X86_IO_APIC 1
index 1d5f14ad62867ac2f077697c95e5645755b9fa7b..6c090e6e4fe4252581cf397d53dd438d3baa8a99 100644 (file)
@@ -18,7 +18,8 @@
 #ifndef _LINUX_IN_H
 #define _LINUX_IN_H
 
-#include <linux/types.h>
+#include <xeno/types.h>
+#include <xeno/socket.h>
 
 /* Standard well-defined IP protocols.  */
 enum {